# MadSnake - A snake game
# Copyright (C) 2020-2021  zhiqiang.bzq
#
# See LICENSE. And if you have interest in this project, join us.
#
# zhiqiang.bzq
# bzq23@foxmail.com

import pygame
from pagectr import *
from common import *
import snake
import ground
import rule
from color import Color
from item import *

class GamePage(object):
  SNAKE_LIST = [
    snake.ThiefSnake, snake.WarriorSnake, snake.MageSnake,
  ]
  def __init__(self, scoreboardheight, groundsize, groundunitsize):
    self.scoreboard_height_ = scoreboardheight
    self.ground_size_ = groundsize
    self.ground_unit_size_ = groundunitsize
    self.automove_interval_ = 1.
    self.good_interval_ = 5.
    self.game_time_ = 180.
    self.rule_ = None
    self.ground_ = None
    self.result_ = None
    self.snakes_ = {}

  def SnakeForOccupation(self, id, occu):
    name = "Snake%d"%id
    snake = GamePage.SNAKE_LIST[occu.id](name, id)
    snake.OnInitGround(self.ground_)
    return snake

  def OnLoad(self, result):
    keys = sorted(result.result.keys())
    if len(keys) > MAX_SNAKE_COUNT:
      raise TooManySnakeException()
    self.ground_ = ground.Ground(self.ground_size_)
    self.result_ = None
    self.snakes_ = { k: self.SnakeForOccupation(k, result.result[k]) for k in keys }
    self.rule_ = rule.Rule(self.game_time_)

  def OnKeyboard(self, playerid, action):
    self.ground_.OnEvent()
    if playerid not in self.snakes_: return
    self.snakes_[playerid].OnEvent(action, self.snakes_)

  def OnRender(self, screen):
    # timer drive.
    body_points = []
    for snake in self.snakes_.values():
      snake.OnTimer(self.automove_interval_)
      body_points.extend(snake.Body())
    self.ground_.OnGenerating(body_points, self.good_interval_)
    # rule check.
    self.result_ = self.rule_.Gaze(self.snakes_, self.ground_)
    # clear all.
    screen.fill(Color.BLACK)
    # render score & bufs
    self.RenderScoreBoard(screen)
    # render ground.
    self.RenderGround(screen)
    # render snake.
    self.RenderSnakes(screen)

  def RenderGround(self, screen):  
    for loc, item in self.ground_.ItemMap().items():
      rect = pygame.Rect(self.ground_unit_size_.width * loc[0],
                          self.ground_unit_size_.height * loc[1] + self.scoreboard_height_,
                          self.ground_unit_size_.width, self.ground_unit_size_.height)
      pygame.draw.rect(screen, self.ground_.ColorForLocation(loc), rect, 0)

  def RenderSnakes(self, screen):
    for snake in self.snakes_.values():
      body = snake.Body()
      for i in range(len(body)):
        rect = pygame.Rect(self.ground_unit_size_.width * body[i].x,
                            self.ground_unit_size_.height * body[i].y + self.scoreboard_height_,
                            self.ground_unit_size_.width, self.ground_unit_size_.height)
        pygame.draw.rect(screen, snake.BodyColor(i), rect, 0)
  
  def RenderScoreBoardForPlayer(self, screen, playerid):
    if playerid not in self.snakes_: return
    at_left = (playerid == 0)
    snake = self.snakes_[playerid]

    score_font = pygame.font.SysFont('arial', 32, True)
    buf_font = pygame.font.SysFont('arial', 12, True)
    player_font =  pygame.font.SysFont('arial', 24, True)
    skill_font = pygame.font.SysFont('arial', 12, True)

    player_words = player_font.render(snake.Name(), True, snake.BodyColor(0), Color.BLACK)
    score_words = score_font.render("%d"%snake.Score(), True, Color.WHITE, Color.BLACK)
    # for skill
    skill_cd = snake.SkillColdDown()
    if skill_cd > 0:
      skill_words = skill_font.render("%s %.1f"%(snake.Skill(), skill_cd), True, Color.RED, Color.BLACK)
    else:
      skill_words = skill_font.render("%s Ready"%(snake.Skill()), True, Color.GREEN, Color.BLACK)
    # for bufs
    bufs_words = []
    for buf in snake.Bufs():
      buf_words = buf_font.render("%s %.1f"%(Item.NameForType(buf), snake.LeftTimeForBuf(buf)), True, Item.ColorForType(buf), Color.BLACK)
      bufs_words.append(buf_words)
    # arrangement
    sidewidth = max([player_words.get_width(), score_words.get_width(), skill_words.get_width()])
    y = 25
    if at_left:
      screen.blit(player_words, ((sidewidth - player_words.get_width()) / 2 + 20, y))
    else:
      screen.blit(player_words, (screen.get_width() - 20 - sidewidth + (sidewidth - player_words.get_width()) / 2, y))
    y += player_words.get_height() + 5
    if at_left:
      screen.blit(score_words, ((sidewidth - score_words.get_width()) / 2 + 20, y))
    else:
      screen.blit(score_words, (screen.get_width() - 20 - sidewidth + (sidewidth - score_words.get_width()) / 2, y))
    y += score_words.get_height() + 5
    if at_left:
      screen.blit(skill_words, ((sidewidth - skill_words.get_width()) / 2 + 20, y))
    else:
      screen.blit(skill_words, (screen.get_width() - 20 - sidewidth + (sidewidth - skill_words.get_width()) / 2, y))

    if len(bufs_words) > 0:
      rightsidewidth = max([ x.get_width() for x in bufs_words ])
      y = 20
      for buf_words in bufs_words:
        if at_left:
          screen.blit(buf_words, (sidewidth + 5 + 20, y))
        else:
          screen.blit(buf_words, (screen.get_width() - 20 - sidewidth - 5 - buf_words.get_width(), y))
        y += buf_words.get_height() + 2

  def RenderScoreBoard(self, screen):
    for i in self.snakes_.keys():
      self.RenderScoreBoardForPlayer(screen, i)

    time_font = pygame.font.SysFont('arial', 48, True)
    vs_font = pygame.font.SysFont('arial', 24, True)
    lefttime = self.rule_.LeftTime()
    time_words = time_font.render("%.0f"%lefttime, True, Color.WHITE if lefttime > 10 else Color.RandomColor(), Color.BLACK)
    vs_words = vs_font.render("vs", True, Color.WHITE, Color.BLACK)
    y = (self.scoreboard_height_ - time_words.get_height()) / 2
    screen.blit(time_words, ((screen.get_width() - time_words.get_width()) / 2, y))
    y += time_words.get_height() + 1
    screen.blit(vs_words, ((screen.get_width() - vs_words.get_width()) / 2, y))
    
  def OnCheckResult(self):
    if self.result_ is None or not self.result_.over: return None
    return PageResult(self.result_)

